import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.text.csv.CsvUtil;

import java.util.*;

/**
 * @author jcl_hqu
 * @date 2021/4/20 19:58
 */




    public class VirtualOperateSystem {
    /**
     * @description: processList 所有进程的信息
     * priorityReadyQueue 用于SJF算法的优先队列
     * readyQueue FCFS算法的就绪队列
     * running 标识此时有进程运行
     * running_process 正在运行的进程
     * @param: null
     * @return:
     * @author jcl_hqu
     * @date: 2021/4/25 11:26
     */
    List<VirtualProcess> processList;

    /**定义优先队列，并且按服务时间排序**/
    Queue<VirtualProcess> priorityReadyQueue = new PriorityQueue<>(new Comparator<VirtualProcess>() {
        @Override
        public int compare(VirtualProcess o1, VirtualProcess o2) {
            if (o1.getCpu_burst() < o2.getCpu_burst()) return -1;
            if (o1.getCpu_burst() == o2.getCpu_burst()) return 0;
            return 1;
        }
    });
    Queue<VirtualProcess> readyQueue = new LinkedList<>(); // 就绪队列
    boolean running = false; // cpu此时是否执行进程
    VirtualProcess running_process; // 运行的进程


    /**
     * @description: 构造函数
     * @param: 所有虚拟进程需要执行的信息
     * @return:
     * @author jcl_hqu
     * @date: 2021/4/24 9:24
     */
    VirtualOperateSystem(List processes) {
        processList = new ArrayList<>(processes);
    }


    private double[] calAve(List<VirtualProcess> result_list) {
        /**
         * @description: 计算平均周转时间、平均等待时间
         * @param: result_list
         * @return:
         * @author jcl_hqu
         * @date: 2021/4/29 11:20
         */
        double AverageTAT = 0;
        double AverageWTAT = 0;
        double AverageWT = 0;
        double num = result_list.size();
        for (VirtualProcess p : result_list) {
            AverageTAT += p.getTurnaround_time();
            AverageWTAT += p.getWeighted_turnaround_time();
            AverageWT += p.getWait_time();
        }

        AverageTAT /= num;
        AverageWTAT /= num;
        AverageWT /= num;
        return new double[]{AverageTAT, AverageWTAT, AverageWT};
    }

    private void calResult(Double time) {
        /**
         * @description: 计算到达时间、周转时间、等待时间
         * @param: time
         * @return:
         * @author jcl_hqu
         * @date: 2021/4/29 11:22
         */
        running_process.start_time = time;
        running_process.finish_time = time + running_process.cpu_burst;
        running_process.wait_time = time - running_process.getArrival_time();
        running_process.turnaround_time = running_process.finish_time - running_process.arrival_time;
        running_process.weighted_turnaround_time = running_process.turnaround_time / running_process.cpu_burst;
    }

    public void printResult(List<VirtualProcess> list) {
        /**
         * @description:
         *   打印运行结果
         */

        System.out.println();
        System.out.format("%16s  %16s  %16s  %16s \n", "Process Num.", " Turnaround Time", "WeightedTurnaround Time", "Waiting Time");
        for (VirtualProcess vp : list) {
            System.out.format("%14d     %14.2f     %14.2f     %14.2f \n", vp.id, vp.turnaround_time, vp.weighted_turnaround_time, vp.wait_time);
        }
    }

    private String getQueueIdList(Queue<VirtualProcess> readyQueue) {
        StringBuilder readyQueue_id = new StringBuilder("");//结果存在字符串中

        // 迭代器访问结果
        Iterator<VirtualProcess> iterator = readyQueue.iterator();
        while (iterator.hasNext()) {
            readyQueue_id.append(iterator.next().id + " ");
        }
        return readyQueue_id.toString();
    }


    public double[] FCFS_algorithm() {
        /**
         * @description: 先来先服务算法模拟
         * @param:
         * @return:  平均结果
         * @author jcl_hqu
         * @date: 2021/4/29 11:33
         */
        System.out.println("FCFS Running");
        List<VirtualProcess> result_list = new LinkedList<>();//结果链表
        int job_counts;//记录未工作的进程数量

        Double time = 0.0;//记录当前运行时间
        List<VirtualProcess> processes = new ArrayList<VirtualProcess>(processList);
        job_counts = processList.size();

        /**
         *  先按到达时间进行排序
         *
         * **/
        Collections.sort(processes, new Comparator<VirtualProcess>() {
            public int compare(VirtualProcess p1, VirtualProcess p2) {
                double p1Arrival_time = p1.getArrival_time();
                double p2Arrival_time = p2.getArrival_time();
                if (p1Arrival_time < p2Arrival_time) return -1;
                if (p1Arrival_time == p2Arrival_time) return 0;
                return 1;
            }
        });
        System.out.println("Process Num.    Start Time   End Time   Ready Queue");

        while (true) {

            /** 到达时间等于此时虚拟操作系统运行时间放入就绪队列**/
            for (VirtualProcess process : processes) {
                if (process.getArrival_time() == time&&!readyQueue.contains(process)) readyQueue.offer(process);
            }

            if (job_counts == 0) break; //运行结束跳出循环

            /** 根据此时是否有进程执行  **/
            if (running == false) {
                // 就绪队列出队，运行进程
                running = true;
                running_process = readyQueue.poll();

                /**
                 * @description:
                 *  计算完成时间、周转时间、带权周转时间
                 */
                calResult(time);
                result_list.add(running_process);
                time += 1;//运行时间+1
            } else {
                time += 1;
                if (running_process.finish_time == (time - 1)) {
                    // 运行结束停止运行
                    time -= 1;
                    running = false;
                    String readyQueue_id = getQueueIdList(readyQueue);//得到就绪队列中的进程
                    System.out.format("%8d     %8.2f     %8.2f     %8s \n", running_process.id, running_process.start_time, running_process.finish_time, readyQueue_id);
                    job_counts--;//运行完毕，未运行数量-1
                }
            }
        }
        printResult(result_list);//打印结果
        return calAve(result_list);//返回平均
    }


    public double[] SJF_algorithm() {
        /**
         * @description: 短作业优先算法
         * @param:
         * @return:
         * @author jcl_hqu
         * @date: 2021/4/29 11:41
         */
        System.out.println("SJF Running");
        List<VirtualProcess> result_list = new LinkedList<>();
        int job_counts;
        Double time = 0.0;
        List<VirtualProcess> processes = new ArrayList<>(processList);
        job_counts = processList.size();

        System.out.println("Process Num.    Start Time   End Time   Ready Queue");
        while (true) {
            /** 放入就绪队列**/
            for (VirtualProcess process : processes) {
                if (process.getArrival_time() == time && !priorityReadyQueue.contains(process)) {
                    priorityReadyQueue.offer(process); //由于是优先队列，会根据服务时间大小自动排好序
                }
            }
            if (job_counts == 0) break;

            /** 队头服务时间最短出队运行**/
            if (running == false) {
                running_process = priorityReadyQueue.poll();
                running = true;
                calResult(time);
                result_list.add(running_process);
                time += 1;
            } else {
                time += 1;
                if ((time - 1) == running_process.getFinish_time()) {
                    time -= 1;
                    running = false;
                    String readyQueue_id = getQueueIdList(priorityReadyQueue);
                    System.out.format("%8d     %8.2f     %8.2f     %8s \n", running_process.id, running_process.start_time, running_process.finish_time, readyQueue_id.toString());
                    job_counts--;
                }
            }
        }

        printResult(result_list);
        return calAve(result_list);
    }

//    public double[] HRRN(){
//
//    }
//
//    public double[] DD_algorithm(){
//
//    }

    public static void main(String[] args) {

        // 读取csv文件
        CsvReader reader = CsvUtil.getReader();
        CsvData data = reader.read(FileUtil.file(System.getProperty("user.dir") + "./EX3/res/testData.csv"));
        List<CsvRow> rows = data.getRows();
        List<VirtualProcess> virtualProcessList = new ArrayList<>();
        boolean flag = false;//不写第一行到VirtualProcess中
        for (CsvRow csvRow : rows) {
            if (!flag) {
                flag = true;
                continue;
            }
            Long id = Long.valueOf(csvRow.getRawList().get(0));
            Long arrival_time = Long.valueOf(csvRow.getRawList().get(1));
            Long service_time = Long.valueOf(csvRow.getRawList().get(2));

            virtualProcessList.add(new VirtualProcess(id, arrival_time, service_time));
        }

        VirtualOperateSystem virtualOperateSystem = new VirtualOperateSystem(virtualProcessList);

        /**菜单操作**/
//        System.out.println("菜单");
//        Scanner scanner=new Scanner(System.in);
//        String  key=scanner.nextLine();
//        switch (key){
//            case "F":
//                virtualOperateSystem.FCFS_algorithm();break;
//            case "S":
//                virtualOperateSystem.SJF_algorithm();break;
//            default:
//                break;
//        }


        /**运行两个算法**/
        double[] sjf_algorithm = virtualOperateSystem.SJF_algorithm();
        double[] fcfs_algorithm = virtualOperateSystem.FCFS_algorithm();
        //输出平均结果
        System.out.println("Algorithm    Average TAT   Average WTAT   Average WT");
        System.out.format("%8s    %8.2f     %8.2f     %8.2f      \n", "FCFS", fcfs_algorithm[0], fcfs_algorithm[1], fcfs_algorithm[2]);
        System.out.format("%8s    %8.2f     %8.2f     %8.2f      \n", "SJF", sjf_algorithm[0], sjf_algorithm[1], sjf_algorithm[2]);
    }

}
